/*
* Copyright (c) 2025 Shenzhen Kaihong Digital Industry Development Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


// export var time_ms = 0;
// export function FreshTime() {
//     let t = new Date()
//     time_ms = t.getTime()
// }
// FreshTime()
// export function TimeMS() {
//     let t = new Date()
//     return t.getTime()
// }

// export function GetURL() {
//     if ("undefined" != typeof wx) {
//         return "https://7465-testegg-19e3c9-1301193145.tcb.qcloud.la/"
//     }
//     else return ""
// }

// for i in range(360):
//  a=i*3.1415926/180
//  x=cos(a)
//  y=sin(a)
//  if x==0:continue
//  t1=atan(y/x)*180/3.1415926
//  t2=atan2(y,x)*180/3.1415926
//  print("%5d,(%3.2f,%3.2f),%3.2f,%3.2f"%(i,x,y,t1,t2))
class XTools {
    static RGBA(r, g, b, a) {
        if (a == undefined) {
            a = 0xff;
        }
        return a << 24 | r << 16 | g << 8 | b
    }
    static fDot(f, d) {
        let r = Math.pow(10, d);
        return Math.round(f * r) / r;
        // return parseFloat(f.toFixed(d));
    }
    static RandInt(min = 0, max = 100) {//包含max
        return Math.floor(Math.random() * (max - min + 1)) + min
    }
    static IncludedAngle(x1, y1, x2, y2, x3, y3) {
        let v1 = [x2 - x1, y2 - y1];
        let v2 = [x2 - x3, y2 - y3];
        function dot(v1, v2) {
            return v1[0] * v2[0] + v1[1] * v2[1];
        }
        function length(v) {
            return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
        }
        let cosTheta = dot(v1, v2) / (length(v1) * length(v2));
        let theta = Math.acos(cosTheta) * 180 / Math.PI;
        return theta;
    }
    static fAngle(x, y) {
        return Math.atan2(-y, x) * 180 / Math.PI
    }
    static LineRect(x1, y1, x2, y2, x, y, w, h) {//射线和矩形交点
        if (y1 == y2) {
            if (x2 < x1) {
                return [x, y1];
            }
            else {
                return [x + w, y1];
            }
        }
        if (x1 == x2) {
            if (y2 < y1) {
                return [y, x1];
            }
            else return [y + h, x1];
        }
        let k = (x1 - x2) / (y1 - y2);
        let x3, y3;
        if (y2 < y1) {
            y3 = y;
        }
        else {
            y3 = y + h;
        }
        x3 = x1 - (y1 - y3) * k;
        if (x3 >= x && x3 <= x + w) {
            return [x3, y3];
        }
        else {
            if (x2 < x1) {
                x3 = x;
            }
            else {
                x3 = x + w;
            }
            y3 = y1 - (x1 - x3) / k;
            if (y3 >= y && y3 <= y + h) {
                return [x3, y3];
            }
            else {
                console.log("err");
            }
        }
        return [0, 0];
    }
    static iDistance(x, y) {
        return Math.sqrt(x * x + y * y)
    }
    static InRect(xx, yy, x, y, w, h) {
        if (xx < x) return false;
        if (xx >= x + w) return false;
        if (yy < y) return false;
        if (yy >= y + h) return false;
        return true;
    }
    static InCircle(xx, yy, x, y, radius, a1, a2) {
        if (XTools.iDistance(xx - x, yy - y) > radius) return false;
        let am = XTools.fAngle(xx - x, yy - y) - 360;
        while (am < a1) am += 360;
        if (am > a2) return false;
        return true;
    }
    static GetTimeSec() {
        return parseInt(XTools.TIME_MS / 1000);
    }
    static FRAME_AUTOINCRASE = 0;
    static FRAME_SECOND = 0;
    static CALC_FPS = [];
    static FPS_MS = 0;
    static FPS_NUM = 0;
    static TIME_MS = 0;
    static Update() {
        // let d = new Date();
        // XTools.TIME_MS = d.getTime();
        XTools.TIME_MS = Date.now();
        XTools.FRAME_AUTOINCRASE += 1;
        XTools.CALC_FPS.push(XTools.TIME_MS);
        if (XTools.CALC_FPS.length > 30) {
            XTools.FPS_MS = (XTools.CALC_FPS[30] - XTools.CALC_FPS[0]) / 30;
            XTools.FPS_NUM = (1000 / XTools.FPS_MS).toFixed(2);
            XTools.CALC_FPS.shift();
        }
        XTools.FRAME_SECOND = parseInt(XTools.TIME_MS / 1000);
    }
    static MOUSE_POS = {
        x: 0,
        y: 0,
        down: false,
        rdown: false,
    }
    static mouseIn(x,y,w,h){
        return x < XTools.MOUSE_POS.x && XTools.MOUSE_POS.x < x + w && y < XTools.MOUSE_POS.y && XTools.MOUSE_POS.y < y + h;
    }
    static KEY_CTRL = false;
    static KEY_SHIFT = false;
    static KEY_ALT = false;

    static RandSelect(arr) {
        return arr[XTools.RandInt(0, arr.length - 1)];
    }

    static CopyToClip(textToCopy) {
        //navigator.clipboard.writeText(GNode.GetPath(node));
        let textArea = document.createElement("textarea");
        textArea.value = textToCopy;
        // 使text area不在viewport，同时设置不可见
        textArea.style.position = "absolute";
        textArea.style.opacity = 0;
        textArea.style.left = "-999999px";
        textArea.style.top = "-999999px";
        document.body.appendChild(textArea);
        textArea.focus();
        textArea.select();
        // return new Promise((res, rej) => {
        //     // 执行复制命令并移除文本框
        document.execCommand('copy')// ? res() : rej();
        textArea.remove();
        // });
    }

    static SCALE_TEXT = 1;
    static SNAP_SHOT = false;
    static SERVER_ADDR = "ccnto.x3322.net:6789";
    static MODE_DEV = false;
    static DEV_IP = "192.168.169.130";
    static GLOBAL_DPR = 1;

    static GenToken(length) {
        let token = '';
        const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

        for (let i = 0; i < length; i++) {
            const randomIndex = Math.floor(Math.random() * characters.length);
            token += characters.charAt(randomIndex);
        }

        return token;
    }

    static TEXT_ENCODER = new TextEncoder();
    static TEXT_DECODER = new TextDecoder();
    static StringToBase64(s) {
        if (typeof window !== 'undefined') {
            let data = this.TEXT_ENCODER.encode(s);
            // let ts = String.fromCharCode.apply(null, data);
            var ts2 = data.reduce((string, code) => string + String.fromCharCode(code), '');
            return btoa(ts2);
        }
        else {
            return Buffer.from(s).toString('base64');
        }
    }
    static Base64TOString(s) {
        if (typeof window !== 'undefined') {
            let decodedStr = atob(s);
            return this.TEXT_DECODER.decode(new Uint8Array([...decodedStr].map(char => char.charCodeAt(0))));
        }
        else {
            return Buffer.from(s, 'base64').toString();
        }
    }

    static DownloadStringAsFile(filename, content) {
        const element = document.createElement('a');
        element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(content));
        element.setAttribute('download', filename);
        element.style.display = 'none';
        document.body.appendChild(element);
        element.click();
        document.body.removeChild(element);
    }
    static downloadUrlAsFile(filename, url) {
        const element = document.createElement('a');
        element.setAttribute('href', url);
        element.setAttribute('download', filename);
        element.style.display = 'none';
        document.body.appendChild(element);
        element.click();
        document.body.removeChild(element);
    }

    static isWindows() {
        return this.getOS() == "Windows";
    }
    static isMobile() {//只有左键点击，没有右键
        return ["Android", "iPhone", "iPad", "MacIntel"].indexOf(this.getOS()) >= 0;
    }

    static getOS() {
        if (/Windows/.test(navigator.userAgent)) {
            return 'Windows';
        } else if (/Android/.test(navigator.userAgent)) {
            return 'Android';
        } else if (/Linux/.test(navigator.userAgent)) {
            return 'Linux';
        }
        if ('userAgentData' in navigator && navigator.userAgentData.platform) {
            return navigator.userAgentData.platform;
        } else if (navigator.platform) {
            return navigator.platform;
        } else {
            return 'Unknown';
        }
        // var userAgent = window.navigator.userAgent,
        //     platform = window.navigator.platform,
        //     macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'],
        //     windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'],
        //     iosPlatforms = ['iPhone', 'iPad', 'iPod'],
        //     os = null;
        // if (macosPlatforms.indexOf(platform) !== -1) {
        //     os = 'Mac OS';
        // } else if (iosPlatforms.indexOf(platform) !== -1) {
        //     os = 'iOS';
        // } else if (windowsPlatforms.indexOf(platform) !== -1) {
        //     os = 'Windows';
        // } else if (/Android/.test(userAgent)) {
        //     os = 'Android';
        // } else if (!os && /Linux/.test(platform)) {
        //     os = 'Linux';
        // }
        // return os;
    }

    static ClearString(s) {//清除字符串中转义字符和引号
        return s.replace(/\\|"|'|`|\n|\r/g, "_");
    }

    static isValidVariableName(s) {
        // 使用u修饰符来支持Unicode
        const regex = /^\p{L}[\p{L}\p{N}_$]*$/u;
        return regex.test(s);
    }

    static GLOBAL_STR = "";

    // static AUTO_LOGIN = "192.168.169.129:65432";
    static AUTO_LOGIN = "192.168.169.129:54321";
    // static AUTO_LOGIN = false;

    static ENABLE_COMPRESS = false;

    static RUNTIME_OX = 0;
    static RUNTIME_OY = 0;
    static RUNTIME_UPDATE_LINES = false;

    static TOKEN_RECORD = [];
    static GenToken(length) {
        let token = '';
        const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

        while (true) {
            for (let i = 0; i < length; i++) {
                const randomIndex = Math.floor(Math.random() * characters.length);
                token += characters.charAt(randomIndex);
            }
            if (XTools.TOKEN_RECORD.indexOf(token) == -1) {
                XTools.TOKEN_RECORD.push(token);
                break;
            }
        }
        return token;
    }
}

var g_root = [null];

module.exports = {
    XTools,
    g_root
}
